#ifndef __M_CONSUMER_H__
#define __M_CONSUMER_H__
#include <iostream>
#include <string>
#include <unordered_map>
#include <memory>
#include <vector>
#include <mutex>
#include <sstream>
#include <unordered_map>
#include "../mqcommon/mq_msg.pb.h"
#include "../mqcommon/mq_loger.hpp"
#include "../mqcommon/mq_helper.hpp"

namespace mq{
                                            //消费者标识，消息属性，消息内容
using ConsumerCallback = std::function<void(const std::string&,const mq::BasicProperties* bp,const std::string&)>;
//消费者管理结构
struct Consumer{
    std::string tag;//消费者标识
    std::string qname;//消费者订阅的队列名称
    bool auto_ack;//自动确认标识
    ConsumerCallback callback;//回调函数

    Consumer(){
        DLOG("new Consumer：%p ",this);
    }
    Consumer(const std::string& ctag,const std::string& queue_name,bool ack_flag,const ConsumerCallback &cb)
                                :tag(ctag),qname(queue_name),auto_ack(ack_flag),callback(std::move(cb)){
        DLOG("new Consumer：%p ",this);

    }

    ~Consumer(){
        DLOG("del Consumer：%p ",this);//查看地址防止资源泄露
    }

    using ptr = std::shared_ptr<Consumer>;
};

//队列为单元的消费者管理结构
class QueueConsumer{
private:
    std::mutex _mutex;//锁
    std::string _qname;//队列名称
    size_t _rr_seq;//轮转序号
    std::vector<Consumer::ptr> _consumers;//存储消费者队列（本质使用vector存）
public:
    QueueConsumer(const std::string qname):_qname(qname),_rr_seq(0){}

//创建消费者
    Consumer::ptr create(const std::string& ctag,const std::string& queue_name,
            bool ack_flag,const ConsumerCallback& cb){
        
        std::unique_lock<std::mutex> lock(_mutex);//加锁
        //判断消费者是否重复，若重复则不用创建了
        for(auto& consumer : _consumers){
            if(consumer->tag == ctag){
                //若找到相等，则表示已存在
                DLOG("消费者:%s创建失败，因为已存在",ctag.c_str());
                return Consumer::ptr();//返回一个空的对象回去
            }
        }

        //若不存在则，首先需要自己创建一个对象，然后再插入到队列中
        auto consumer = std::make_shared<Consumer>(ctag,queue_name,ack_flag,cb);
        _consumers.push_back(consumer);
        return consumer;
    }

//删除指定消费者
    void remove(const std::string& ctag){
        std::unique_lock<std::mutex> lock(_mutex);//加锁

        for(auto it = _consumers.begin(); it < _consumers.end() ; it++){
            if((*it)->tag == ctag){
               //若查找到了，就删除
               _consumers.erase(it);
                return;
            }
        }
        DLOG("消费者:%s删除失败，因为不存在!",ctag.c_str());
    }

//获取消费者：以RR轮转按序获取
    Consumer::ptr choose(){
        std::unique_lock<std::mutex> lock(_mutex);//加锁

        if(_consumers.size() == 0){
            //如果为空，则返回空对象
            DLOG("获取消费者失败，因为队列为空！");
            return Consumer::ptr();
        }

        //获取轮转序号
        int idx = _rr_seq % _consumers.size();
        _rr_seq++;//获取后对序号进行++，给后面使用

        return _consumers[idx];
    }

    bool empty(){
        std::unique_lock<std::mutex> lock(_mutex);//加锁
        return _consumers.size() == 0;
    }

    bool exists(const std::string& ctag){
        std::unique_lock<std::mutex> lock(_mutex);//加锁
        for(auto& consumer : _consumers){//遍历查找
            if(consumer->tag == ctag){
                return true;//找到返回真
            }
        }
        return false;//出循环代表没有找到返回假
    }

    void clear(){
        std::unique_lock<std::mutex> lock(_mutex);//加锁
        
        //调用容器的清理所有消息
        _consumers.clear();
        _rr_seq = 0;

    }

    using ptr = std::shared_ptr<QueueConsumer>;
};

class ConsumerManager{
private:
    std::mutex _mutex;
    std::unordered_map<std::string,QueueConsumer::ptr> _qconsumers;

public:
    ConsumerManager(){}

    using ptr = std::shared_ptr<ConsumerManager>;
//创建消费者队列
    void initQueueConsumer(const std::string& qname){
        std::unique_lock<std::mutex> lock(_mutex);//加锁

        //判断是否重复
        auto it = _qconsumers.find(qname);
        if(it != _qconsumers.end()){
            //不等于end，则表示队列已存在
            // DLOG("初始化消费者管理队列失败，消费者管理队列：%s已存在",qname.c_str());    
            return ;
        }

        //新增
        auto qconsumer = std::make_shared<QueueConsumer>(qname);
        _qconsumers.insert({qname,qconsumer});
    }

//销毁消费者队列
    void destroyQueueConsumer(const std::string& qname){
        std::unique_lock<std::mutex> lock(_mutex);//加锁

        _qconsumers.erase(qname);
    }

//创建消息给指定队列
    Consumer::ptr create(const std::string& ctag,const std::string& queue_name,
            bool ack_flag,const ConsumerCallback& cb){

        QueueConsumer::ptr cp;
        {
            std::unique_lock<std::mutex> lock(_mutex);//加锁
            
            //判断所需插入的消息的队列是否存在!
            auto it = _qconsumers.find(queue_name);
            if(it == _qconsumers.end()){
                DLOG("创建消息给指定队列失败，消费者管理队列:%s不存在 ",queue_name.c_str());
                return Consumer::ptr();
            }
            cp = it->second;
            // DLOG("获取到订阅的队列：%s",it->first.c_str());
        }
       
        return cp->create(ctag,queue_name,ack_flag,cb);
    }

//删除指定队列消费者
    void remove(const std::string& ctag,const std::string& queue_name){
        QueueConsumer::ptr cp;
        {
            std::unique_lock<std::mutex> lock(_mutex);//加锁
            
            //判断所需插入的消息的队列是否存在!
            auto it = _qconsumers.find(queue_name);
            if(it == _qconsumers.end()){
                DLOG("删除指定队列消费者失败，消费者管理队列:%s不存在 ",queue_name.c_str());
                return ;
            }
            cp = it->second;
        }
        return cp->remove(ctag);
    }


//选择队列消费者
    Consumer::ptr choose(const std::string& queue_name){
        QueueConsumer::ptr cp;
        {
            std::unique_lock<std::mutex> lock(_mutex);//加锁
            
            //判断所需插入的消息的队列是否存在!
            auto it = _qconsumers.find(queue_name);
            if(it == _qconsumers.end()){
                DLOG("选择队列消费者失败，消费者管理队列:%s不存在 ",queue_name.c_str());
                return  Consumer::ptr();
            }
            cp = it->second;
        }
        return cp->choose();
    }

//判断队列是否为空
    bool empty(const std::string& queue_name){
        QueueConsumer::ptr cp;
        {
            std::unique_lock<std::mutex> lock(_mutex);//加锁
            
            //判断所需插入的消息的队列是否存在!
            auto it = _qconsumers.find(queue_name);
            if(it == _qconsumers.end()){
                DLOG("判断队列是否为空失败，消费者管理队列:%s不存在 ",queue_name.c_str());
                return false;
            }
            cp = it->second;
        }
        return cp->empty();
    }

//判断队列中的某个消费者是否存在
    bool exists(const std::string& ctag,const std::string& queue_name){
        QueueConsumer::ptr cp;
        {
            std::unique_lock<std::mutex> lock(_mutex);//加锁
            
            //判断所需插入的消息的队列是否存在!
            auto it = _qconsumers.find(queue_name);
            if(it == _qconsumers.end()){
                DLOG("判断队列中的某个消费者是否存在失败，消费者管理队列:%s不存在 ",queue_name.c_str());
                return false;
            }
            cp = it->second;
        }
        return cp->exists(ctag);
    }

    void clear(){
        std::unique_lock<std::mutex> lock(_mutex);//加锁
        _qconsumers.clear();
    }

};
}


#endif